module $Xrm {
    export class _string {
        static isGuid(value: string): bool {
            return /[a-z0-9]{8}(?:-[a-z0-9]{4}){3}-[a-z0-9]{12}/i.test(value)
        }

        static isNumber(value: string): bool {
            return /^\d+$/.test(value);
        }

        static format(...args: string[]): string { // avoid crappy string concats and use this method to keep things looking nice
            var s = args[0];
            for (var i = 0; i < args.length - 1; i++) {
                var reg = new RegExp("\\{" + i + "\\}", "gm");
                s = s.replace(reg, args[i + 1]);
            }
            return s;
        }

        static insert(s: string, position: number, value: string) {
            return s.substring(0, position) + value + s.substring(position);
        }

        static pad(value: any, length?: number) {
            value = String(value);
            length = length || 2;

            while (value.length < length) {
                value = "0" + value;
            }

            return value;
        };
    }

    export class _array {
        static getLength(array: any): number { // need this because js objects are strange, .length doesnt work if you use a string indexer since js treats it as a property/object on the object itself
            var count = 0;
            for (var field in array) {
                count++;
            }
            return count;
        }

        static joinWithFormat(array: any, format: string): string {
            var result = "";
            for (var i = 0; i < array.length; i++) {
                result += _string.format(format, array[i]);
            }
            return result;
        }
    }

    export class _xml {
        static getText(node): string {
            return node != undefined ? (node.text !== undefined ? node.text : node.textContent) : null; // cross browser support
        }

        static getValue(node): any { // cross browser support, returns any type so we can determine type later if needed
            var value = node.text !== undefined ? node.text : node.textContent;

            // hacky methods to figure out data types
            if (value == "true" || value == "false") { return value == "true"; }
            else if (_string.isNumber(value)) { return parseInt(value); }

            return value;
        }

        // no xpath support for cross browser so here's a poor mans approach
        static getChildNode(node, nodeName: string) {
            for (var i = 0; i < node.childNodes.length; i++) {
                var childNode = node.childNodes[i];
                if (childNode.nodeName === nodeName) {
                    return childNode;
                }
            }
            return null;
        }

        static getAttribute(node, attributeName: string) {
            for (var i = 0; i < node.attributes.length; i++) {
                if (node.attributes[i].nodeName == attributeName) {
                    return node.attributes[i];
                }
            }

            return null;
        }

        static stripNamespace(nodeName: string): string { // makes it easier to compare/generate dynamic objects without the ugly looking namespaces
            if (nodeName.indexOf(":") > -1) {
                return nodeName.substring(nodeName.indexOf(":") + 1);
            }
            return nodeName;
        }
    }

    export class _date { // this is not a complete dateformatter, you'll see some format parameters dont exist, this was built to handle crm webservice datetime along with few other scenarios
        static format(date: Date, mask: string) {
            var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMs])\1?|[LloSZ]|"[^"]*"|'[^']*'/g;

            var _ = "get",
                d = date[_ + "Date"](),
                D = date[_ + "Day"](),
                m = date[_ + "Month"](),
                y = date[_ + "FullYear"](),
                H = date[_ + "Hours"](),
                M = date[_ + "Minutes"](),
                s = date[_ + "Seconds"](),
                L = date[_ + "Milliseconds"](),
                o = date.getTimezoneOffset(),
                flags = {
                    d: d,
                    dd: _string.pad(d),
                    m: m + 1,
                    mm: _string.pad(m + 1),
                    yy: String(y).slice(2),
                    yyyy: y,
                    h: H % 12 || 12,
                    hh: _string.pad(H % 12 || 12),
                    H: H,
                    HH: _string.pad(H),
                    M: M,
                    MM: _string.pad(M),
                    s: s,
                    ss: _string.pad(s),
                    l: _string.pad(L, 3),
                    L: _string.pad(L, 7),
                    t: H < 12 ? "a" : "p",
                    tt: H < 12 ? "am" : "pm",
                    T: H < 12 ? "A" : "P",
                    TT: H < 12 ? "AM" : "PM",
                    o: (o > 0 ? "-" : "+") + _string.insert(_string.pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), 2, ":"),
                    S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
                };

            return mask.replace(token, function ($0) {
                return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
            });
        }
    }
}